package br.com.educa.modelo.financeiro;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceContext;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.json.RooJson;
import org.springframework.roo.addon.serializable.RooSerializable;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.transaction.annotation.Transactional;

import br.com.educa.modelo.financeiro.enumerator.TipoLancamento;
import br.com.educa.modelo.publico.Controle;
import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;

@Entity
@Table
@Configurable
@RooSerializable
@RooJson
@RooJavaBean
@RooToString
@RooJpaActiveRecord(finders = { "findMovimentacoesCaixasByCaixa" })
public class MovimentacoesCaixas implements Serializable {

	@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

	@Version
    @Column(name = "version")
    private Integer version;
	
    @ManyToOne
    @JoinColumn(name = "controle", referencedColumnName = "id")
    private Controle controle;
	
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(style = "M-")
    private Date dataMovimentacao;
    
    @NotNull
    private Double valorMovimentacao;
    
    @ManyToOne
    @JoinColumn
    private Historicos historico;
    
    @ManyToOne
    @JoinColumn
    private Caixas caixa;
    
    @ManyToOne
    @JoinColumn
    private PlanoContas contaDebito;
    
    @ManyToOne
    @JoinColumn
    private PlanoContas contaCredito;
    
    private String especiePagamento;
    
    @Enumerated(EnumType.STRING)
    private TipoLancamento tipoLancamento;
    
    private String documento;
    
    private String observacao;
    
    private String tipoPagamento;
	
    @ManyToOne
    @JoinColumn(name = "negociacao", referencedColumnName = "id")
    private Negociacoes negociacao;
    
    @ManyToOne
    @JoinColumn(name = "cheque", referencedColumnName = "id")
    private Cheques cheque;

	public Long getId() {
        return this.id;
    }

	public void setId(Long id) {
        this.id = id;
    }

	public Integer getVersion() {
        return this.version;
    }

	public void setVersion(Integer version) {
        this.version = version;
    }

	@PersistenceContext
    transient EntityManager entityManager;

	public static final EntityManager entityManager() {
        EntityManager em = new MovimentacoesCaixas().entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }

	public static long countMovimentacoesCaixases() {
        return entityManager().createQuery("SELECT COUNT(o) FROM MovimentacoesCaixas o", Long.class).getSingleResult();
    }

	public static List<MovimentacoesCaixas> findAllMovimentacoesCaixases() {
        return entityManager().createQuery("SELECT o FROM MovimentacoesCaixas o", MovimentacoesCaixas.class).getResultList();
    }

	public static MovimentacoesCaixas findMovimentacoesCaixas(Long id) {
        if (id == null) return null;
        return entityManager().find(MovimentacoesCaixas.class, id);
    }

	public static List<MovimentacoesCaixas> findMovimentacoesCaixasEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM MovimentacoesCaixas o", MovimentacoesCaixas.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

	@Transactional
    public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

	@Transactional
    public void remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            MovimentacoesCaixas attached = MovimentacoesCaixas.findMovimentacoesCaixas(this.id);
            this.entityManager.remove(attached);
        }
    }

	@Transactional
    public void flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.flush();
    }

	@Transactional
    public void clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.clear();
    }

	@Transactional
    public MovimentacoesCaixas merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        MovimentacoesCaixas merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }

	public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }

	public String toJson() {
        return new JSONSerializer().exclude("*.class").serialize(this);
    }

	public static MovimentacoesCaixas fromJsonToMovimentacoesCaixas(String json) {
        return new JSONDeserializer<MovimentacoesCaixas>().use(null, MovimentacoesCaixas.class).deserialize(json);
    }

	public static String toJsonArray(Collection<MovimentacoesCaixas> collection) {
        return new JSONSerializer().exclude("*.class").serialize(collection);
    }

	public static Collection<MovimentacoesCaixas> fromJsonArrayToMovimentacoesCaixases(String json) {
        return new JSONDeserializer<List<MovimentacoesCaixas>>().use(null, ArrayList.class).use("values", MovimentacoesCaixas.class).deserialize(json);
    }

	private static final long serialVersionUID = 1L;

	public Negociacoes getNegociacao() {
        return this.negociacao;
    }

	public void setNegociacao(Negociacoes negociacao) {
        this.negociacao = negociacao;
    }

	public Date getDataMovimentacao() {
		return dataMovimentacao;
	}

	public void setDataMovimentacao(Date dataMovimentacao) {
		this.dataMovimentacao = dataMovimentacao;
	}

	public Double getValorMovimentacao() {
		return valorMovimentacao;
	}

	public void setValorMovimentacao(Double valorMovimentacao) {
		this.valorMovimentacao = valorMovimentacao;
	}

	public Caixas getCaixa() {
		return caixa;
	}

	public void setCaixa(Caixas caixa) {
		this.caixa = caixa;
	}

	public PlanoContas getContaDebito() {
		return contaDebito;
	}

	public void setContaDebito(PlanoContas contaDebito) {
		this.contaDebito = contaDebito;
	}

	public PlanoContas getContaCredito() {
		return contaCredito;
	}

	public void setContaCredito(PlanoContas contaCredito) {
		this.contaCredito = contaCredito;
	}

	public TipoLancamento getTipoLancamento() {
		return tipoLancamento;
	}

	public void setTipoLancamento(TipoLancamento tipoLancamento) {
		this.tipoLancamento = tipoLancamento;
	}

	public String getDocumento() {
		return documento;
	}

	public void setDocumento(String documento) {
		this.documento = documento;
	}

	public String getObservacao() {
		return observacao;
	}

	public void setObservacao(String observacao) {
		this.observacao = observacao;
	}

	public String getTipoPagamento() {
		return tipoPagamento;
	}

	public void setTipoPagamento(String tipoPagamento) {
		this.tipoPagamento = tipoPagamento;
	}

	public Historicos getHistorico() {
        return this.historico;
    }

	public void setHistorico(Historicos historico) {
        this.historico = historico;
    }

	public String getEspeciePagamento() {
        return this.especiePagamento;
    }

	public void setEspeciePagamento(String especiePagamento) {
        this.especiePagamento = especiePagamento;
    }

	public Cheques getCheque() {
        return this.cheque;
    }

	public void setCheque(Cheques cheque) {
        this.cheque = cheque;
    }

	public Controle getControle() {
        return this.controle;
    }

	public void setControle(Controle controle) {
        this.controle = controle;
    }
	
    public static TypedQuery<br.com.educa.modelo.financeiro.MovimentacoesCaixas> findMovimentacoesCaixasByCaixa(Caixas caixa) {
        if (caixa == null) throw new IllegalArgumentException("The caixa argument is required");
        EntityManager em = MovimentacoesCaixas.entityManager();
        TypedQuery<MovimentacoesCaixas> q = em.createQuery("SELECT o FROM MovimentacoesCaixas AS o WHERE o.caixa = :caixa ORDER BY dataMovimentacao, id", MovimentacoesCaixas.class);
        q.setParameter("caixa", caixa);
        return q;
    }
        
    public static List<HashMap<String, Object>> findMovimentacoesCaixasByLancamentos(Long caixa) {
        EntityManager em = MovimentacoesCaixas.entityManager();
    	List<HashMap<String, Object>> lancamentos = new ArrayList<HashMap<String, Object>>();
    	List<Object[]> resultSet = new ArrayList<Object[]>();
        javax.persistence.Query q = entityManager().createNativeQuery("SELECT sum(o.valor_movimentacao) as valor_movimentacao, o.negociacao, o.data_movimentacao, o.observacao, o.tipo_lancamento, o.tipo_pagamento FROM movimentacoes_caixas AS o WHERE o.caixa = ? GROUP BY o.negociacao, o.data_movimentacao, o.observacao, o.tipo_lancamento, o.tipo_pagamento ORDER BY o.data_movimentacao, o.negociacao");
        ((javax.persistence.Query) q).setParameter(1, caixa);
    	resultSet = ((javax.persistence.Query) q).getResultList();
    	BigDecimal valor = new BigDecimal(0.00d);
    	for (Object[] row : resultSet) {
			HashMap<String,Object> objetoResultado = new HashMap<String, Object>();
			objetoResultado.put("valor_movimentacao",((BigDecimal)row[0]).setScale(2,BigDecimal.ROUND_HALF_DOWN));
			objetoResultado.put("negociacao",((BigInteger)row[1]).intValue());
			objetoResultado.put("data_movimentacao",(Date) row[2]);
			objetoResultado.put("observacao",row[3].toString());
			objetoResultado.put("tipo_lancamento",row[4].toString());
			objetoResultado.put("tipo_pagamento",row[5].toString());
			lancamentos.add(objetoResultado);
		}
    	return lancamentos;
    }
}
